package com.luochen.cdpt.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.luochen.cdpt.response.RespBean;
import com.luochen.cdpt.eneity.User;
import com.luochen.cdpt.service.CustomUserService;
import com.luochen.cdpt.util.MD5Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class CdptSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	CustomUserService userService;

	@Autowired
	CustomMetadataSource metadataSource;

	@Autowired
	UrlAccessDecisionManager urlAccessDecisionManager;

	@Autowired
	AuthenticationAccessDeniedHandler deniedHandler;

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userService).passwordEncoder(new PasswordEncoder(){
			@Override
			public String encode(CharSequence rawPassword) {
				return MD5Util.encode(rawPassword.toString());
			}
			@Override
			public boolean matches(CharSequence rawPassword, String encodedPassword) {
				return rawPassword.equals(encodedPassword);
			}
		});
	}

	@Override
	public void configure(WebSecurity web)  {
		web.ignoring().antMatchers("/login.html", "/app", "/css/**", "/images/**", "/js/**", "/json/**", "/oauthLogin",
				"/session_expired","/uploadimg","/images/**","/druid/**");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry
				= http.authorizeRequests();
		registry.requestMatchers(CorsUtils::isPreFlightRequest).permitAll();//让Spring security放行所有preflight request
		http.authorizeRequests()
				.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
			@Override
			public <O extends FilterSecurityInterceptor> O postProcess(O o) {
				o.setSecurityMetadataSource(metadataSource);
				o.setAccessDecisionManager(urlAccessDecisionManager);
				return o;
			}
		}).and().formLogin().loginPage("/oauthLogin").loginProcessingUrl("/login").usernameParameter("username")
				.passwordParameter("password").failureHandler((req, resp, e) -> {
					resp.setContentType("application/json;charset=utf-8");
					RespBean respBean;
					if (e instanceof BadCredentialsException || e instanceof UsernameNotFoundException) {
						respBean = RespBean.error("账户名或者密码输入错误!");
					}else if(e instanceof  LockedException || e instanceof  DisabledException){
						respBean = RespBean.error("用户账号已被禁用,请联系管理员!");
					}else {
						respBean = RespBean.error("登录失败!"+e.getMessage());
					}
					print(resp,respBean);
				}).successHandler((req, resp, auth) -> {
					resp.setContentType("application/json;charset=utf-8");
					RespBean respBean = RespBean.ok("登录成功!",
							SecurityContextHolder.getContext().getAuthentication().getPrincipal());
					print(resp,respBean);
				}).permitAll().and()
				.cors().and().csrf().disable().headers().frameOptions().disable().and().exceptionHandling()
				.accessDeniedHandler(deniedHandler);
	}


	@Bean
	public LogoutSuccessHandler logoutSuccessHandler() { //登出处理
		return (httpServletRequest, httpServletResponse, authentication) -> {
			try {
				User user = (User) authentication.getPrincipal();
				log.info("USER : " + user.getUsername() + " LOGOUT SUCCESS !  ");
			} catch (Exception e) {
				log.info("LOGOUT EXCEPTION , e : " + e.getMessage());
			}
			RespBean respBean = RespBean.ok("注销成功!");
			print(httpServletResponse,respBean);
		};
	}

	/**
	 * response输出
	 * @param response
	 * @param respBean
	 */
	private void print(HttpServletResponse response,RespBean respBean){
		try {
			ObjectMapper om = new ObjectMapper();
			PrintWriter out = response.getWriter();
			out.write(om.writeValueAsString(respBean));
			out.flush();
			out.close();
		}catch (Exception e){
			e.printStackTrace();
		}
	}
}